---
title: Asynchronous Programming Pattern Conversion
description: From Python's asyncio to JavaScript's Promise and async/await, master core concepts of asynchronous programming and pattern conversion, understand differences in event loop mechanisms.
---

# Asynchronous Programming Pattern Conversion

Asynchronous programming is one of the biggest challenges Python developers face when transitioning to JavaScript. While Python's asyncio and JavaScript's Promise/async-await share similar concepts, they differ significantly in implementation and usage. This module will help you understand these differences and master JavaScript's core asynchronous programming skills.

## Fundamentals of Asynchronous Programming

### Synchronous vs Asynchronous Comparison

<PythonEditor title="Synchronous vs Asynchronous Comparison" compare={true}>
```python !! py
# Python synchronous and asynchronous programming comparison
import asyncio
import time
import requests
from concurrent.futures import ThreadPoolExecutor

# 1. Synchronous programming example
def sync_fetch_data(url):
    """Synchronously fetch data"""
    print(f"Starting request: {url}")
    # Simulate network request
    time.sleep(2)
    print(f"Completed request: {url}")
    return f"Data from {url}"

def sync_main():
    """Synchronous main function"""
    start_time = time.time()
    
    urls = [
        "https://api.example1.com",
        "https://api.example2.com",
        "https://api.example3.com"
    ]
    
    results = []
    for url in urls:
        result = sync_fetch_data(url)
        results.append(result)
    
    end_time = time.time()
    print(f"Synchronous execution time: {end_time - start_time:.2f} seconds")
    return results

# 2. Asynchronous programming example (asyncio)
async def async_fetch_data(url):
    """Asynchronously fetch data"""
    print(f"Starting async request: {url}")
    # Simulate async network request
    await asyncio.sleep(2)
    print(f"Completed async request: {url}")
    return f"Async data from {url}"

async def async_main():
    """Asynchronous main function"""
    start_time = time.time()
    
    urls = [
        "https://api.example1.com",
        "https://api.example2.com", 
        "https://api.example3.com"
    ]
    
    # Execute multiple async tasks concurrently
    tasks = [async_fetch_data(url) for url in urls]
    results = await asyncio.gather(*tasks)
    
    end_time = time.time()
    print(f"Asynchronous execution time: {end_time - start_time:.2f} seconds")
    return results

# 3. Python async context manager
class AsyncDatabaseConnection:
    def __init__(self, db_url):
        self.db_url = db_url
        self.connection = None
    
    async def __aenter__(self):
        print(f"Connecting to database: {self.db_url}")
        await asyncio.sleep(0.1)  # Simulate connection time
        self.connection = f"Connected to {self.db_url}"
        return self.connection
    
    async def __aexit__(self, exc_type, exc_val, exc_tb):
        print("Closing database connection")
        await asyncio.sleep(0.1)  # Simulate close time
        self.connection = None

async def database_operation():
    async with AsyncDatabaseConnection("postgresql://localhost") as conn:
        print(f"Using connection: {conn}")
        await asyncio.sleep(1)  # Simulate database operation
        return "Query result"

# Run examples
print("=== Python Asyncio Examples ===")
# sync_main()  # Takes ~6 seconds
# asyncio.run(async_main())  # Takes ~2 seconds
# asyncio.run(database_operation())

# 4. AsyncIO patterns
async def producer(queue):
    """Producer coroutine"""
    for i in range(5):
        await asyncio.sleep(0.1)
        await queue.put(f"item-{i}")
        print(f"Produced: item-{i}")
    await queue.put(None)  # Signal end

async def consumer(queue, name):
    """Consumer coroutine"""
    while True:
        item = await queue.get()
        if item is None:
            break
        await asyncio.sleep(0.2)
        print(f"Consumer {name} processed: {item}")
        queue.task_done()

async def producer_consumer_example():
    """Producer-consumer pattern"""
    queue = asyncio.Queue()
    
    # Start producer and consumers
    await asyncio.gather(
        producer(queue),
        consumer(queue, "A"),
        consumer(queue, "B")
    )

print("Producer-Consumer pattern with asyncio")
# asyncio.run(producer_consumer_example())
```

```javascript !! js
// JavaScript asynchronous programming
// Modern JavaScript (ES2017+) async/await

// 1. Synchronous programming example (blocking)
function syncFetchData(url) {
    console.log(`Starting request: ${url}`);
    // JavaScript doesn't have built-in sleep, simulate with busy wait (DON'T DO THIS)
    const start = Date.now();
    while (Date.now() - start < 2000) {
        // Blocking the main thread - very bad practice!
    }
    console.log(`Completed request: ${url}`);
    return `Data from ${url}`;
}

function syncMain() {
    const startTime = Date.now();
    
    const urls = [
        "https://api.example1.com",
        "https://api.example2.com",
        "https://api.example3.com"
    ];
    
    const results = [];
    for (const url of urls) {
        const result = syncFetchData(url);
        results.push(result);
    }
    
    const endTime = Date.now();
    console.log(`Synchronous execution time: ${(endTime - startTime) / 1000} seconds`);
    return results;
}

// 2. Promise-based asynchronous programming
function fetchDataPromise(url) {
    console.log(`Starting promise request: ${url}`);
    
    return new Promise((resolve, reject) => {
        // Simulate async network request
        setTimeout(() => {
            console.log(`Completed promise request: ${url}`);
            resolve(`Promise data from ${url}`);
        }, 2000);
    });
}

function promiseMain() {
    const startTime = Date.now();
    
    const urls = [
        "https://api.example1.com",
        "https://api.example2.com",
        "https://api.example3.com"
    ];
    
    // Execute all promises concurrently
    const promises = urls.map(url => fetchDataPromise(url));
    
    return Promise.all(promises).then(results => {
        const endTime = Date.now();
        console.log(`Promise execution time: ${(endTime - startTime) / 1000} seconds`);
        return results;
    });
}

// 3. Async/await syntax (modern JavaScript)
async function asyncFetchData(url) {
    console.log(`Starting async request: ${url}`);
    
    // Use Promise-based timeout
    await new Promise(resolve => setTimeout(resolve, 2000));
    
    console.log(`Completed async request: ${url}`);
    return `Async data from ${url}`;
}

async function asyncMain() {
    const startTime = Date.now();
    
    const urls = [
        "https://api.example1.com",
        "https://api.example2.com",
        "https://api.example3.com"
    ];
    
    // Execute multiple async operations concurrently
    const promises = urls.map(url => asyncFetchData(url));
    const results = await Promise.all(promises);
    
    const endTime = Date.now();
    console.log(`Async/await execution time: ${(endTime - startTime) / 1000} seconds`);
    return results;
}

// 4. Error handling in async functions
async function asyncWithErrorHandling(url) {
    try {
        const response = await fetch(url);
        
        if (!response.ok) {
            throw new Error(`HTTP error! status: ${response.status}`);
        }
        
        const data = await response.json();
        return data;
    } catch (error) {
        console.error(`Error fetching ${url}:`, error.message);
        throw error; // Re-throw if needed
    }
}

// 5. JavaScript async patterns
async function producer(queue) {
    for (let i = 0; i < 5; i++) {
        await new Promise(resolve => setTimeout(resolve, 100));
        queue.push(`item-${i}`);
        console.log(`Produced: item-${i}`);
    }
    queue.push(null); // Signal end
}

async function consumer(queue, name) {
    while (true) {
        // Simple polling (real implementation would use better patterns)
        while (queue.length === 0) {
            await new Promise(resolve => setTimeout(resolve, 10));
        }
        
        const item = queue.shift();
        if (item === null) {
            break;
        }
        
        await new Promise(resolve => setTimeout(resolve, 200));
        console.log(`Consumer ${name} processed: ${item}`);
    }
}

async function producerConsumerExample() {
    const queue = [];
    
    // Start producer and consumers concurrently
    await Promise.all([
        producer(queue),
        consumer(queue, "A"),
        consumer(queue, "B")
    ]);
}

// Run examples
console.log("=== JavaScript Async Examples ===");
// asyncMain().then(results => console.log(results));
// producerConsumerExample();

// 6. Fetch API example (browser/Node.js with node-fetch)
async function realFetchExample() {
    try {
        const response = await fetch('https://jsonplaceholder.typicode.com/posts/1');
        const data = await response.json();
        console.log('Fetched data:', data);
        return data;
    } catch (error) {
        console.error('Fetch error:', error);
    }
}

// 7. Promise utilities
const promiseUtilities = {
    // Delay utility
    delay: (ms) => new Promise(resolve => setTimeout(resolve, ms)),
    
    // Timeout wrapper
    withTimeout: (promise, ms) => {
        const timeout = new Promise((_, reject) =>
            setTimeout(() => reject(new Error('Timeout')), ms)
        );
        return Promise.race([promise, timeout]);
    },
    
    // Retry utility
    retry: async (fn, maxAttempts = 3, delay = 1000) => {
        for (let attempt = 1; attempt <= maxAttempts; attempt++) {
            try {
                return await fn();
            } catch (error) {
                if (attempt === maxAttempts) {
                    throw error;
                }
                console.log(`Attempt ${attempt} failed, retrying in ${delay}ms...`);
                await promiseUtilities.delay(delay);
            }
        }
    }
};

// Example usage of utilities
async function utilityExample() {
    // Using delay
    console.log('Starting...');
    await promiseUtilities.delay(1000);
    console.log('1 second later');
    
    // Using timeout
    const slowOperation = () => promiseUtilities.delay(3000);
    try {
        await promiseUtilities.withTimeout(slowOperation(), 2000);
    } catch (error) {
        console.log('Operation timed out');
    }
    
    // Using retry
    const flakyOperation = () => {
        if (Math.random() < 0.7) {
            throw new Error('Random failure');
        }
        return 'Success!';
    };
    
    try {
        const result = await promiseUtilities.retry(flakyOperation, 3, 500);
        console.log('Retry result:', result);
    } catch (error) {
        console.log('All retry attempts failed');
    }
}
```
</PythonEditor>

### Event Loop Differences

<PythonEditor title="Event Loop Mechanisms" compare={true}>
```python !! py
# Python asyncio event loop
import asyncio
import time
import threading
from concurrent.futures import ThreadPoolExecutor

# 1. Understanding Python's event loop
async def understand_python_event_loop():
    """Python asyncio event loop characteristics"""
    
    # Get current event loop
    loop = asyncio.get_running_loop()
    
    print(f"Event loop: {loop}")
    print(f"Loop is running: {loop.is_running()}")
    print(f"Thread ID: {threading.get_ident()}")
    
    # Schedule coroutines
    async def task1():
        print("Task 1 started")
        await asyncio.sleep(1)
        print("Task 1 completed")
        return "Result 1"
    
    async def task2():
        print("Task 2 started")
        await asyncio.sleep(0.5)
        print("Task 2 completed")
        return "Result 2"
    
    # Run tasks concurrently
    results = await asyncio.gather(task1(), task2())
    print(f"Results: {results}")

# 2. CPU-bound vs I/O-bound tasks
async def cpu_vs_io_bound():
    """Comparing CPU-bound and I/O-bound tasks"""
    
    def cpu_bound_task(n):
        """CPU-intensive task"""
        result = 0
        for i in range(n):
            result += i ** 2
        return result
    
    async def io_bound_task(delay):
        """I/O-intensive task"""
        await asyncio.sleep(delay)
        return f"I/O task completed after {delay}s"
    
    # I/O-bound tasks work well with asyncio
    start_time = time.time()
    io_results = await asyncio.gather(
        io_bound_task(1),
        io_bound_task(1),
        io_bound_task(1)
    )
    io_time = time.time() - start_time
    print(f"I/O-bound tasks (concurrent): {io_time:.2f}s")
    
    # CPU-bound tasks don't benefit from asyncio (use ThreadPoolExecutor)
    loop = asyncio.get_running_loop()
    with ThreadPoolExecutor() as executor:
        start_time = time.time()
        cpu_results = await asyncio.gather(
            loop.run_in_executor(executor, cpu_bound_task, 1000000),
            loop.run_in_executor(executor, cpu_bound_task, 1000000),
            loop.run_in_executor(executor, cpu_bound_task, 1000000)
        )
        cpu_time = time.time() - start_time
        print(f"CPU-bound tasks (threaded): {cpu_time:.2f}s")

# 3. Asyncio coordination primitives
async def asyncio_coordination():
    """Asyncio coordination primitives"""
    
    # Event
    event = asyncio.Event()
    
    async def waiter(name, event):
        print(f"{name} waiting for event")
        await event.wait()
        print(f"{name} received event")
    
    async def setter(event):
        await asyncio.sleep(2)
        print("Setting event")
        event.set()
    
    # Semaphore
    semaphore = asyncio.Semaphore(2)  # Allow 2 concurrent operations
    
    async def limited_resource(name, semaphore):
        async with semaphore:
            print(f"{name} acquired resource")
            await asyncio.sleep(1)
            print(f"{name} released resource")
    
    # Lock
    lock = asyncio.Lock()
    shared_resource = 0
    
    async def critical_section(name, lock):
        async with lock:
            global shared_resource
            temp = shared_resource
            await asyncio.sleep(0.1)  # Simulate work
            shared_resource = temp + 1
            print(f"{name} incremented resource to {shared_resource}")
    
    # Run coordination examples
    await asyncio.gather(
        waiter("Waiter1", event),
        waiter("Waiter2", event),
        setter(event)
    )

# 4. Error handling in asyncio
async def asyncio_error_handling():
    """Error handling patterns in asyncio"""
    
    async def failing_task(should_fail=True):
        await asyncio.sleep(0.5)
        if should_fail:
            raise ValueError("Task failed!")
        return "Success"
    
    # Handle individual task errors
    try:
        result = await failing_task(True)
    except ValueError as e:
        print(f"Caught error: {e}")
    
    # Handle errors in gather
    try:
        results = await asyncio.gather(
            failing_task(False),
            failing_task(True),
            failing_task(False),
            return_exceptions=True  # Don't stop on first exception
        )
        
        for i, result in enumerate(results):
            if isinstance(result, Exception):
                print(f"Task {i} failed: {result}")
            else:
                print(f"Task {i} succeeded: {result}")
    
    except Exception as e:
        print(f"Gather failed: {e}")

# Run asyncio examples
if __name__ == "__main__":
    print("=== Python Asyncio Event Loop ===")
    asyncio.run(understand_python_event_loop())
    asyncio.run(cpu_vs_io_bound())
    asyncio.run(asyncio_coordination())
    asyncio.run(asyncio_error_handling())
```

```javascript !! js
// JavaScript event loop and asynchronous execution
// Understanding the JavaScript event loop

// 1. Understanding JavaScript's event loop
function understandJSEventLoop() {
    console.log("=== JavaScript Event Loop ===");
    
    // Synchronous code
    console.log("1. Synchronous - Start");
    
    // setTimeout (macrotask)
    setTimeout(() => {
        console.log("4. Macrotask - setTimeout");
    }, 0);
    
    // Promise (microtask)
    Promise.resolve().then(() => {
        console.log("3. Microtask - Promise");
    });
    
    // More synchronous code
    console.log("2. Synchronous - End");
    
    // Microtasks have higher priority than macrotasks
    // Output order: 1, 2, 3, 4
}

// 2. Microtasks vs Macrotasks
function microtasksVsMacrotasks() {
    console.log("\n=== Microtasks vs Macrotasks ===");
    
    console.log("Start");
    
    // Macrotasks
    setTimeout(() => console.log("setTimeout 1"), 0);
    setTimeout(() => console.log("setTimeout 2"), 0);
    
    // Microtasks
    Promise.resolve().then(() => console.log("Promise 1"));
    Promise.resolve().then(() => console.log("Promise 2"));
    
    // queueMicrotask (explicit microtask)
    queueMicrotask(() => console.log("queueMicrotask"));
    
    console.log("End");
    
    // Output: Start, End, Promise 1, Promise 2, queueMicrotask, setTimeout 1, setTimeout 2
}

// 3. Promise execution timing
async function promiseExecutionTiming() {
    console.log("\n=== Promise Execution Timing ===");
    
    console.log("1. Before promise");
    
    const promise = new Promise((resolve) => {
        console.log("2. Inside Promise constructor (synchronous)");
        resolve("Promise resolved");
    });
    
    console.log("3. After promise creation");
    
    promise.then((value) => {
        console.log("4. Promise then:", value);
    });
    
    console.log("5. After promise.then");
    
    // Using async/await
    const result = await Promise.resolve("Awaited result");
    console.log("6. Awaited:", result);
}

// 4. Event loop phases (Node.js specific)
function nodeEventLoopPhases() {
    console.log("\n=== Node.js Event Loop Phases ===");
    
    // Immediate (check phase)
    setImmediate(() => console.log("setImmediate"));
    
    // Timer phase
    setTimeout(() => console.log("setTimeout"), 0);
    
    // I/O callbacks phase would be here
    
    // Poll phase - where most async operations happen
    
    // Check phase - setImmediate callbacks
    
    // Close callbacks phase
    
    process.nextTick(() => console.log("nextTick 1"));
    process.nextTick(() => console.log("nextTick 2"));
    
    // Note: process.nextTick has highest priority (runs before microtasks)
    Promise.resolve().then(() => console.log("Promise"));
    
    console.log("Synchronous");
}

// 5. Async coordination patterns
class AsyncCoordination {
    // Event-like pattern using Promise
    static createEvent() {
        let resolveEvent;
        const eventPromise = new Promise(resolve => {
            resolveEvent = resolve;
        });
        
        return {
            wait: () => eventPromise,
            trigger: (value) => resolveEvent(value)
        };
    }
    
    // Semaphore pattern
    static createSemaphore(limit) {
        let current = 0;
        const queue = [];
        
        return {
            async acquire() {
                return new Promise(resolve => {
                    if (current < limit) {
                        current++;
                        resolve();
                    } else {
                        queue.push(resolve);
                    }
                });
            },
            
            release() {
                if (queue.length > 0) {
                    const resolve = queue.shift();
                    resolve();
                } else {
                    current--;
                }
            }
        };
    }
    
    // Mutex pattern
    static createMutex() {
        let locked = false;
        const queue = [];
        
        return {
            async lock() {
                return new Promise(resolve => {
                    if (!locked) {
                        locked = true;
                        resolve();
                    } else {
                        queue.push(resolve);
                    }
                });
            },
            
            unlock() {
                if (queue.length > 0) {
                    const resolve = queue.shift();
                    resolve();
                } else {
                    locked = false;
                }
            }
        };
    }
}

// 6. Error handling in async JavaScript
async function asyncErrorHandling() {
    console.log("\n=== Async Error Handling ===");
    
    // Function that might fail
    async function mightFail(shouldFail = false) {
        await new Promise(resolve => setTimeout(resolve, 100));
        if (shouldFail) {
            throw new Error("Operation failed!");
        }
        return "Success";
    }
    
    // Try-catch with async/await
    try {
        const result = await mightFail(true);
        console.log(result);
    } catch (error) {
        console.log("Caught error:", error.message);
    }
    
    // Promise.allSettled for handling multiple promises
    const promises = [
        mightFail(false),
        mightFail(true),
        mightFail(false)
    ];
    
    const results = await Promise.allSettled(promises);
    results.forEach((result, index) => {
        if (result.status === 'fulfilled') {
            console.log(`Promise ${index} resolved:`, result.value);
        } else {
            console.log(`Promise ${index} rejected:`, result.reason.message);
        }
    });
    
    // Global error handlers
    process.on('unhandledRejection', (reason, promise) => {
        console.log('Unhandled Rejection at:', promise, 'reason:', reason);
    });
    
    process.on('uncaughtException', (error) => {
        console.log('Uncaught Exception:', error);
        process.exit(1);
    });
}

// 7. Performance considerations
async function asyncPerformance() {
    console.log("\n=== Async Performance ===");
    
    // Sequential vs concurrent execution
    async function sequentialExample() {
        const start = performance.now();
        
        await new Promise(resolve => setTimeout(resolve, 100));
        await new Promise(resolve => setTimeout(resolve, 100));
        await new Promise(resolve => setTimeout(resolve, 100));
        
        const end = performance.now();
        console.log(`Sequential: ${end - start}ms`);
    }
    
    async function concurrentExample() {
        const start = performance.now();
        
        await Promise.all([
            new Promise(resolve => setTimeout(resolve, 100)),
            new Promise(resolve => setTimeout(resolve, 100)),
            new Promise(resolve => setTimeout(resolve, 100))
        ]);
        
        const end = performance.now();
        console.log(`Concurrent: ${end - start}ms`);
    }
    
    await sequentialExample(); // ~300ms
    await concurrentExample(); // ~100ms
}

// Run examples
async function runExamples() {
    understandJSEventLoop();
    
    setTimeout(() => {
        microtasksVsMacrotasks();
    }, 100);
    
    setTimeout(async () => {
        await promiseExecutionTiming();
        
        if (typeof process !== 'undefined') {
            nodeEventLoopPhases();
        }
        
        await asyncErrorHandling();
        await asyncPerformance();
    }, 200);
}

runExamples();
```
</PythonEditor>

## Promise and Async/Await

### Promise Fundamentals

<PythonEditor title="Promise vs Python Coroutines" compare={true}>
```python !! py
# Python coroutines and asyncio patterns
import asyncio
import aiohttp
import aiofiles
from typing import List, Optional
import json

# 1. Python coroutine definition and usage
async def fetch_user_data(user_id: int) -> dict:
    """Fetch user data asynchronously"""
    # Simulate API call
    await asyncio.sleep(0.5)
    return {
        "id": user_id,
        "name": f"User {user_id}",
        "email": f"user{user_id}@example.com"
    }

async def fetch_multiple_users(user_ids: List[int]) -> List[dict]:
    """Fetch multiple users concurrently"""
    tasks = [fetch_user_data(user_id) for user_id in user_ids]
    users = await asyncio.gather(*tasks)
    return users

# 2. Error handling in asyncio
async def fetch_with_error_handling(user_id: int) -> Optional[dict]:
    """Fetch user with error handling"""
    try:
        if user_id < 0:
            raise ValueError("Invalid user ID")
        
        user = await fetch_user_data(user_id)
        return user
    
    except ValueError as e:
        print(f"Validation error: {e}")
        return None
    
    except Exception as e:
        print(f"Unexpected error: {e}")
        return None

# 3. Async context managers
class AsyncHTTPClient:
    def __init__(self):
        self.session = None
    
    async def __aenter__(self):
        self.session = aiohttp.ClientSession()
        return self
    
    async def __aexit__(self, exc_type, exc_val, exc_tb):
        if self.session:
            await self.session.close()
    
    async def get(self, url: str) -> dict:
        async with self.session.get(url) as response:
            return await response.json()

async def http_client_example():
    """Using async context manager"""
    async with AsyncHTTPClient() as client:
        try:
            data = await client.get("https://jsonplaceholder.typicode.com/posts/1")
            print(f"Fetched data: {data.get('title', 'No title')}")
        except Exception as e:
            print(f"HTTP error: {e}")

# 4. Async generators
async def async_number_generator(start: int, count: int):
    """Async generator example"""
    for i in range(start, start + count):
        await asyncio.sleep(0.1)  # Simulate async work
        yield i

async def consume_async_generator():
    """Consume async generator"""
    async for number in async_number_generator(1, 5):
        print(f"Generated: {number}")

# 5. Timeout and cancellation
async def long_running_task():
    """Task that takes a long time"""
    try:
        await asyncio.sleep(10)
        return "Task completed"
    except asyncio.CancelledError:
        print("Task was cancelled")
        raise

async def timeout_example():
    """Demonstrate timeout and cancellation"""
    try:
        # Set timeout
        result = await asyncio.wait_for(long_running_task(), timeout=2.0)
        print(result)
    except asyncio.TimeoutError:
        print("Task timed out")

# 6. Coordination primitives
async def producer_consumer_with_queue():
    """Producer-consumer pattern with asyncio.Queue"""
    queue = asyncio.Queue(maxsize=3)
    
    async def producer():
        for i in range(5):
            await queue.put(f"item-{i}")
            print(f"Produced: item-{i}")
            await asyncio.sleep(0.1)
        
        # Signal end
        await queue.put(None)
    
    async def consumer(name: str):
        while True:
            item = await queue.get()
            if item is None:
                queue.task_done()
                break
            
            print(f"Consumer {name} processing: {item}")
            await asyncio.sleep(0.2)
            queue.task_done()
    
    # Run producer and consumers
    await asyncio.gather(
        producer(),
        consumer("A"),
        consumer("B")
    )

# 7. Real-world example: File processing
async def process_file(filename: str) -> dict:
    """Process a file asynchronously"""
    try:
        async with aiofiles.open(filename, 'r') as file:
            content = await file.read()
            
        # Simulate processing
        await asyncio.sleep(0.1)
        
        return {
            "filename": filename,
            "size": len(content),
            "lines": content.count('\n'),
            "status": "success"
        }
    
    except FileNotFoundError:
        return {
            "filename": filename,
            "status": "error",
            "error": "File not found"
        }

async def batch_file_processing(filenames: List[str]) -> List[dict]:
    """Process multiple files concurrently"""
    semaphore = asyncio.Semaphore(3)  # Limit concurrent file operations
    
    async def process_with_semaphore(filename: str):
        async with semaphore:
            return await process_file(filename)
    
    tasks = [process_with_semaphore(filename) for filename in filenames]
    results = await asyncio.gather(*tasks, return_exceptions=True)
    
    return [result if not isinstance(result, Exception) else 
            {"filename": "unknown", "status": "error", "error": str(result)} 
            for result in results]

# Example usage
async def main():
    print("=== Python Asyncio Examples ===")
    
    # Basic coroutine usage
    user = await fetch_user_data(1)
    print(f"Single user: {user}")
    
    # Multiple concurrent operations
    users = await fetch_multiple_users([1, 2, 3])
    print(f"Multiple users: {len(users)} users fetched")
    
    # Error handling
    result = await fetch_with_error_handling(-1)
    print(f"Error handling result: {result}")
    
    # Async generator
    await consume_async_generator()
    
    # Timeout example
    await timeout_example()
    
    # Producer-consumer
    await producer_consumer_with_queue()

if __name__ == "__main__":
    asyncio.run(main())
```

```javascript !! js
// JavaScript Promises and async/await
// Modern Promise patterns and best practices

// 1. Promise fundamentals
function createBasicPromise(shouldSucceed = true) {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            if (shouldSucceed) {
                resolve("Promise resolved successfully");
            } else {
                reject(new Error("Promise rejected"));
            }
        }, 1000);
    });
}

// Promise chaining
function promiseChaining() {
    console.log("=== Promise Chaining ===");
    
    return createBasicPromise(true)
        .then(result => {
            console.log("First then:", result);
            return "Modified result";
        })
        .then(result => {
            console.log("Second then:", result);
            return createBasicPromise(true); // Return another promise
        })
        .then(result => {
            console.log("Third then:", result);
        })
        .catch(error => {
            console.error("Caught error:", error.message);
        })
        .finally(() => {
            console.log("Finally block executed");
        });
}

// 2. Async/await syntax
async function fetchUserData(userId) {
    // Simulate API call
    await new Promise(resolve => setTimeout(resolve, 500));
    
    return {
        id: userId,
        name: `User ${userId}`,
        email: `user${userId}@example.com`
    };
}

async function fetchMultipleUsers(userIds) {
    // Sequential execution (slower)
    const usersSequential = [];
    for (const userId of userIds) {
        const user = await fetchUserData(userId);
        usersSequential.push(user);
    }
    
    // Concurrent execution (faster)
    const userPromises = userIds.map(userId => fetchUserData(userId));
    const usersConcurrent = await Promise.all(userPromises);
    
    return { usersSequential, usersConcurrent };
}

// 3. Error handling patterns
async function errorHandlingPatterns() {
    console.log("\n=== Error Handling Patterns ===");
    
    // Try-catch with async/await
    async function fetchWithErrorHandling(userId) {
        try {
            if (userId < 0) {
                throw new Error("Invalid user ID");
            }
            
            const user = await fetchUserData(userId);
            return { success: true, data: user };
        } catch (error) {
            return { success: false, error: error.message };
        }
    }
    
    // Test error handling
    const validResult = await fetchWithErrorHandling(1);
    console.log("Valid user:", validResult);
    
    const invalidResult = await fetchWithErrorHandling(-1);
    console.log("Invalid user:", invalidResult);
    
    // Promise.allSettled for handling multiple promises
    const promises = [
        fetchUserData(1),
        Promise.reject(new Error("Simulated error")),
        fetchUserData(3)
    ];
    
    const results = await Promise.allSettled(promises);
    results.forEach((result, index) => {
        if (result.status === 'fulfilled') {
            console.log(`Promise ${index} succeeded:`, result.value.name);
        } else {
            console.log(`Promise ${index} failed:`, result.reason.message);
        }
    });
}

// 4. Promise utilities and patterns
class PromiseUtils {
    // Timeout wrapper
    static withTimeout(promise, timeoutMs) {
        const timeoutPromise = new Promise((_, reject) => {
            setTimeout(() => reject(new Error('Operation timed out')), timeoutMs);
        });
        
        return Promise.race([promise, timeoutPromise]);
    }
    
    // Retry mechanism
    static async retry(fn, maxAttempts = 3, delay = 1000) {
        for (let attempt = 1; attempt <= maxAttempts; attempt++) {
            try {
                return await fn();
            } catch (error) {
                if (attempt === maxAttempts) {
                    throw error;
                }
                console.log(`Attempt ${attempt} failed, retrying in ${delay}ms...`);
                await new Promise(resolve => setTimeout(resolve, delay));
                delay *= 2; // Exponential backoff
            }
        }
    }
    
    // Debounce async function
    static debounce(fn, delay) {
        let timeoutId;
        let latestResolve;
        let latestReject;
        
        return function(...args) {
            return new Promise((resolve, reject) => {
                latestResolve = resolve;
                latestReject = reject;
                
                clearTimeout(timeoutId);
                timeoutId = setTimeout(async () => {
                    try {
                        const result = await fn.apply(this, args);
                        latestResolve(result);
                    } catch (error) {
                        latestReject(error);
                    }
                }, delay);
            });
        };
    }
    
    // Semaphore for limiting concurrency
    static createSemaphore(limit) {
        let current = 0;
        const queue = [];
        
        return {
            async acquire() {
                return new Promise(resolve => {
                    if (current < limit) {
                        current++;
                        resolve();
                    } else {
                        queue.push(resolve);
                    }
                });
            },
            
            release() {
                if (queue.length > 0) {
                    const resolve = queue.shift();
                    resolve();
                } else {
                    current--;
                }
            },
            
            async execute(fn) {
                await this.acquire();
                try {
                    return await fn();
                } finally {
                    this.release();
                }
            }
        };
    }
}

// 5. Real-world examples
class APIClient {
    constructor(baseURL, options = {}) {
        this.baseURL = baseURL;
        this.timeout = options.timeout || 5000;
        this.retries = options.retries || 3;
        this.semaphore = PromiseUtils.createSemaphore(options.concurrency || 5);
    }
    
    async request(endpoint, options = {}) {
        const url = `${this.baseURL}${endpoint}`;
        
        return this.semaphore.execute(async () => {
            return PromiseUtils.retry(async () => {
                const fetchPromise = fetch(url, {
                    method: 'GET',
                    headers: {
                        'Content-Type': 'application/json',
                        ...options.headers
                    },
                    ...options
                });
                
                const response = await PromiseUtils.withTimeout(fetchPromise, this.timeout);
                
                if (!response.ok) {
                    throw new Error(`HTTP ${response.status}: ${response.statusText}`);
                }
                
                return response.json();
            }, this.retries);
        });
    }
    
    async get(endpoint) {
        return this.request(endpoint);
    }
    
    async post(endpoint, data) {
        return this.request(endpoint, {
            method: 'POST',
            body: JSON.stringify(data)
        });
    }
}

// 6. Async iteration and generators
async function* asyncNumberGenerator(start, count) {
    for (let i = start; i < start + count; i++) {
        await new Promise(resolve => setTimeout(resolve, 100));
        yield i;
    }
}

async function consumeAsyncGenerator() {
    console.log("\n=== Async Generator ===");
    
    for await (const number of asyncNumberGenerator(1, 5)) {
        console.log("Generated:", number);
    }
}

// 7. Producer-consumer pattern with async iterators
class AsyncQueue {
    constructor() {
        this.items = [];
        this.resolvers = [];
        this.closed = false;
    }
    
    async put(item) {
        if (this.closed) {
            throw new Error("Queue is closed");
        }
        
        if (this.resolvers.length > 0) {
            const resolve = this.resolvers.shift();
            resolve(item);
        } else {
            this.items.push(item);
        }
    }
    
    async get() {
        if (this.items.length > 0) {
            return this.items.shift();
        }
        
        if (this.closed) {
            return null;
        }
        
        return new Promise(resolve => {
            this.resolvers.push(resolve);
        });
    }
    
    close() {
        this.closed = true;
        // Resolve pending gets with null
        this.resolvers.forEach(resolve => resolve(null));
        this.resolvers = [];
    }
    
    async *[Symbol.asyncIterator]() {
        while (true) {
            const item = await this.get();
            if (item === null) break;
            yield item;
        }
    }
}

async function producerConsumerExample() {
    console.log("\n=== Producer-Consumer Pattern ===");
    
    const queue = new AsyncQueue();
    
    // Producer
    async function producer() {
        for (let i = 0; i < 5; i++) {
            await new Promise(resolve => setTimeout(resolve, 100));
            await queue.put(`item-${i}`);
            console.log(`Produced: item-${i}`);
        }
        queue.close();
    }
    
    // Consumer
    async function consumer(name) {
        for await (const item of queue) {
            console.log(`Consumer ${name} processing: ${item}`);
            await new Promise(resolve => setTimeout(resolve, 200));
        }
        console.log(`Consumer ${name} finished`);
    }
    
    // Run producer and consumers concurrently
    await Promise.all([
        producer(),
        consumer("A"),
        consumer("B")
    ]);
}

// 8. File processing example (Node.js)
async function processFiles(filenames) {
    console.log("\n=== File Processing ===");
    
    const fs = require('fs').promises;
    
    async function processFile(filename) {
        try {
            const content = await fs.readFile(filename, 'utf8');
            
            // Simulate processing
            await new Promise(resolve => setTimeout(resolve, 100));
            
            return {
                filename,
                size: content.length,
                lines: content.split('\n').length,
                status: 'success'
            };
        } catch (error) {
            return {
                filename,
                status: 'error',
                error: error.message
            };
        }
    }
    
    // Limit concurrent file operations
    const semaphore = PromiseUtils.createSemaphore(3);
    
    const promises = filenames.map(filename =>
        semaphore.execute(() => processFile(filename))
    );
    
    return Promise.all(promises);
}

// Run examples
async function runExamples() {
    console.log("=== JavaScript Promise Examples ===");
    
    // Promise chaining
    await promiseChaining();
    
    // Async/await
    const { usersConcurrent } = await fetchMultipleUsers([1, 2, 3]);
    console.log(`\nFetched ${usersConcurrent.length} users concurrently`);
    
    // Error handling
    await errorHandlingPatterns();
    
    // Async generator
    await consumeAsyncGenerator();
    
    // Producer-consumer
    await producerConsumerExample();
    
    // API client example
    const apiClient = new APIClient('https://jsonplaceholder.typicode.com');
    try {
        const post = await apiClient.get('/posts/1');
        console.log('\nAPI Response:', post.title);
    } catch (error) {
        console.error('API Error:', error.message);
    }
}

runExamples().catch(console.error);
```
</PythonEditor>

## Common Async Patterns and Best Practices

### Real-world Async Applications

<PythonEditor title="Practical Async Applications" compare={true}>
```python !! py
# Python real-world async applications
import asyncio
import aiohttp
import aiofiles
import asyncpg
from datetime import datetime
import json
import logging
from typing import List, Dict, Optional

# Setup logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

# 1. Web scraping with rate limiting
class AsyncWebScraper:
    def __init__(self, max_concurrent: int = 5, delay: float = 1.0):
        self.semaphore = asyncio.Semaphore(max_concurrent)
        self.delay = delay
        self.session = None
    
    async def __aenter__(self):
        self.session = aiohttp.ClientSession()
        return self
    
    async def __aexit__(self, exc_type, exc_val, exc_tb):
        if self.session:
            await self.session.close()
    
    async def fetch_page(self, url: str) -> Optional[Dict]:
        async with self.semaphore:  # Rate limiting
            try:
                logger.info(f"Fetching: {url}")
                async with self.session.get(url) as response:
                    if response.status == 200:
                        content = await response.text()
                        return {
                            "url": url,
                            "status": response.status,
                            "content_length": len(content),
                            "timestamp": datetime.now().isoformat()
                        }
                    else:
                        logger.warning(f"HTTP {response.status} for {url}")
                        return None
            
            except Exception as e:
                logger.error(f"Error fetching {url}: {e}")
                return None
            
            finally:
                await asyncio.sleep(self.delay)  # Rate limiting delay

async def scraping_example():
    """Web scraping example with rate limiting"""
    urls = [
        "https://httpbin.org/delay/1",
        "https://httpbin.org/json",
        "https://httpbin.org/uuid",
        "https://httpbin.org/ip",
        "https://httpbin.org/user-agent"
    ]
    
    async with AsyncWebScraper(max_concurrent=2, delay=0.5) as scraper:
        results = []
        for url in urls:
            result = await scraper.fetch_page(url)
            if result:
                results.append(result)
        
        logger.info(f"Scraped {len(results)} pages successfully")
        return results

# 2. Database operations with connection pooling
class AsyncDatabaseManager:
    def __init__(self, database_url: str, pool_size: int = 10):
        self.database_url = database_url
        self.pool_size = pool_size
        self.pool = None
    
    async def create_pool(self):
        """Create connection pool"""
        self.pool = await asyncpg.create_pool(
            self.database_url,
            min_size=1,
            max_size=self.pool_size
        )
        logger.info(f"Database pool created with {self.pool_size} connections")
    
    async def close_pool(self):
        """Close connection pool"""
        if self.pool:
            await self.pool.close()
            logger.info("Database pool closed")
    
    async def execute_query(self, query: str, *args) -> List[Dict]:
        """Execute query and return results"""
        async with self.pool.acquire() as connection:
            try:
                rows = await connection.fetch(query, *args)
                return [dict(row) for row in rows]
            except Exception as e:
                logger.error(f"Query error: {e}")
                raise
    
    async def execute_transaction(self, queries: List[tuple]) -> bool:
        """Execute multiple queries in a transaction"""
        async with self.pool.acquire() as connection:
            try:
                async with connection.transaction():
                    for query, args in queries:
                        await connection.execute(query, *args)
                return True
            except Exception as e:
                logger.error(f"Transaction error: {e}")
                return False

# 3. File processing pipeline
class AsyncFileProcessor:
    def __init__(self, max_workers: int = 4):
        self.semaphore = asyncio.Semaphore(max_workers)
    
    async def read_file(self, filepath: str) -> Optional[str]:
        """Read file asynchronously"""
        try:
            async with aiofiles.open(filepath, 'r', encoding='utf-8') as file:
                return await file.read()
        except FileNotFoundError:
            logger.error(f"File not found: {filepath}")
            return None
        except Exception as e:
            logger.error(f"Error reading {filepath}: {e}")
            return None
    
    async def process_content(self, content: str, filename: str) -> Dict:
        """Process file content"""
        await asyncio.sleep(0.1)  # Simulate processing time
        
        return {
            "filename": filename,
            "lines": len(content.splitlines()),
            "words": len(content.split()),
            "characters": len(content),
            "processed_at": datetime.now().isoformat()
        }
    
    async def write_result(self, result: Dict, output_dir: str):
        """Write processing result"""
        output_file = f"{output_dir}/{result['filename']}_analysis.json"
        
        async with aiofiles.open(output_file, 'w') as file:
            await file.write(json.dumps(result, indent=2))
    
    async def process_file(self, filepath: str, output_dir: str) -> Optional[Dict]:
        """Complete file processing pipeline"""
        async with self.semaphore:
            # Read file
            content = await self.read_file(filepath)
            if content is None:
                return None
            
            # Process content
            filename = filepath.split('/')[-1]
            result = await self.process_content(content, filename)
            
            # Write result
            await self.write_result(result, output_dir)
            
            logger.info(f"Processed: {filepath}")
            return result

# 4. Real-time data streaming
class AsyncDataStreamer:
    def __init__(self):
        self.subscribers = set()
        self.running = False
    
    def subscribe(self, callback):
        """Subscribe to data stream"""
        self.subscribers.add(callback)
    
    def unsubscribe(self, callback):
        """Unsubscribe from data stream"""
        self.subscribers.discard(callback)
    
    async def broadcast(self, data):
        """Broadcast data to all subscribers"""
        if self.subscribers:
            tasks = [callback(data) for callback in self.subscribers]
            await asyncio.gather(*tasks, return_exceptions=True)
    
    async def start_streaming(self):
        """Start data streaming"""
        self.running = True
        counter = 0
        
        while self.running:
            # Generate mock data
            data = {
                "timestamp": datetime.now().isoformat(),
                "counter": counter,
                "value": counter * 2 + 1
            }
            
            await self.broadcast(data)
            counter += 1
            await asyncio.sleep(1)  # Stream every second
    
    def stop_streaming(self):
        """Stop data streaming"""
        self.running = False

async def streaming_example():
    """Data streaming example"""
    streamer = AsyncDataStreamer()
    received_data = []
    
    async def data_handler(data):
        received_data.append(data)
        logger.info(f"Received: {data}")
    
    # Subscribe to stream
    streamer.subscribe(data_handler)
    
    # Start streaming task
    streaming_task = asyncio.create_task(streamer.start_streaming())
    
    # Let it run for 5 seconds
    await asyncio.sleep(5)
    
    # Stop streaming
    streamer.stop_streaming()
    await streaming_task
    
    logger.info(f"Received {len(received_data)} data points")

# 5. Main application orchestrator
async def main_application():
    """Main application demonstrating various async patterns"""
    logger.info("Starting async application")
    
    try:
        # Web scraping
        scraping_results = await scraping_example()
        logger.info(f"Scraping completed: {len(scraping_results)} results")
        
        # File processing
        processor = AsyncFileProcessor(max_workers=2)
        files_to_process = ["file1.txt", "file2.txt", "file3.txt"]
        
        # Create dummy files for testing
        for filename in files_to_process:
            async with aiofiles.open(filename, 'w') as file:
                await file.write(f"Content of {filename}\nLine 2\nLine 3")
        
        # Process files concurrently
        processing_tasks = [
            processor.process_file(filename, "output")
            for filename in files_to_process
        ]
        
        processing_results = await asyncio.gather(*processing_tasks, return_exceptions=True)
        successful_results = [r for r in processing_results if not isinstance(r, Exception)]
        logger.info(f"File processing completed: {len(successful_results)} files processed")
        
        # Data streaming
        await streaming_example()
        
    except Exception as e:
        logger.error(f"Application error: {e}")
    
    finally:
        logger.info("Application shutdown")

# Performance monitoring
class AsyncPerformanceMonitor:
    def __init__(self):
        self.start_time = None
        self.metrics = {}
    
    async def __aenter__(self):
        self.start_time = asyncio.get_event_loop().time()
        return self
    
    async def __aexit__(self, exc_type, exc_val, exc_tb):
        end_time = asyncio.get_event_loop().time()
        self.metrics['total_time'] = end_time - self.start_time
        self.metrics['tasks_created'] = len(asyncio.all_tasks())
        
        logger.info(f"Performance metrics: {self.metrics}")

# Usage example
async def run_with_monitoring():
    """Run application with performance monitoring"""
    async with AsyncPerformanceMonitor() as monitor:
        await main_application()

if __name__ == "__main__":
    # Run the application
    asyncio.run(run_with_monitoring())
```

```javascript !! js
// JavaScript real-world async applications
// Enterprise-grade async patterns and applications

const fs = require('fs').promises;
const path = require('path');

// 1. Web scraping with rate limiting
class AsyncWebScraper {
    constructor(options = {}) {
        this.maxConcurrent = options.maxConcurrent || 5;
        this.delay = options.delay || 1000;
        this.semaphore = this.createSemaphore(this.maxConcurrent);
        this.userAgent = options.userAgent || 'AsyncWebScraper/1.0';
    }
    
    createSemaphore(limit) {
        let current = 0;
        const queue = [];
        
        return {
            async acquire() {
                return new Promise(resolve => {
                    if (current < limit) {
                        current++;
                        resolve();
                    } else {
                        queue.push(resolve);
                    }
                });
            },
            
            release() {
                if (queue.length > 0) {
                    const resolve = queue.shift();
                    resolve();
                } else {
                    current--;
                }
            }
        };
    }
    
    async fetchPage(url) {
        await this.semaphore.acquire();
        
        try {
            console.log(`Fetching: ${url}`);
            
            const response = await fetch(url, {
                headers: {
                    'User-Agent': this.userAgent
                }
            });
            
            if (response.ok) {
                const content = await response.text();
                return {
                    url,
                    status: response.status,
                    contentLength: content.length,
                    timestamp: new Date().toISOString()
                };
            } else {
                console.warn(`HTTP ${response.status} for ${url}`);
                return null;
            }
            
        } catch (error) {
            console.error(`Error fetching ${url}:`, error.message);
            return null;
            
        } finally {
            this.semaphore.release();
            await this.sleep(this.delay);
        }
    }
    
    async scrapeMultiple(urls) {
        const promises = urls.map(url => this.fetchPage(url));
        const results = await Promise.allSettled(promises);
        
        return results
            .filter(result => result.status === 'fulfilled' && result.value)
            .map(result => result.value);
    }
    
    sleep(ms) {
        return new Promise(resolve => setTimeout(resolve, ms));
    }
}

// 2. Database operations with connection pooling
class AsyncDatabaseManager {
    constructor(connectionString, poolSize = 10) {
        this.connectionString = connectionString;
        this.poolSize = poolSize;
        this.pool = [];
        this.activeConnections = 0;
        this.waitingQueue = [];
    }
    
    async createConnection() {
        // Mock database connection
        return {
            id: Math.random().toString(36),
            query: async (sql, params) => {
                await new Promise(resolve => setTimeout(resolve, 50));
                return { sql, params, rows: [] };
            },
            close: async () => {
                await new Promise(resolve => setTimeout(resolve, 10));
            }
        };
    }
    
    async getConnection() {
        return new Promise(async (resolve) => {
            if (this.pool.length > 0) {
                resolve(this.pool.pop());
            } else if (this.activeConnections < this.poolSize) {
                this.activeConnections++;
                const connection = await this.createConnection();
                resolve(connection);
            } else {
                this.waitingQueue.push(resolve);
            }
        });
    }
    
    async releaseConnection(connection) {
        if (this.waitingQueue.length > 0) {
            const resolve = this.waitingQueue.shift();
            resolve(connection);
        } else {
            this.pool.push(connection);
        }
    }
    
    async executeQuery(sql, params = []) {
        const connection = await this.getConnection();
        
        try {
            const result = await connection.query(sql, params);
            return result;
        } finally {
            await this.releaseConnection(connection);
        }
    }
    
    async executeTransaction(queries) {
        const connection = await this.getConnection();
        
        try {
            // Begin transaction
            await connection.query('BEGIN');
            
            const results = [];
            for (const { sql, params } of queries) {
                const result = await connection.query(sql, params);
                results.push(result);
            }
            
            // Commit transaction
            await connection.query('COMMIT');
            return results;
            
        } catch (error) {
            // Rollback on error
            await connection.query('ROLLBACK');
            throw error;
        } finally {
            await this.releaseConnection(connection);
        }
    }
    
    async closePool() {
        // Close all connections
        const closePromises = this.pool.map(conn => conn.close());
        await Promise.all(closePromises);
        this.pool = [];
        this.activeConnections = 0;
    }
}

// 3. File processing pipeline
class AsyncFileProcessor {
    constructor(maxWorkers = 4) {
        this.maxWorkers = maxWorkers;
        this.semaphore = this.createSemaphore(maxWorkers);
    }
    
    createSemaphore(limit) {
        let current = 0;
        const queue = [];
        
        return {
            async acquire() {
                return new Promise(resolve => {
                    if (current < limit) {
                        current++;
                        resolve();
                    } else {
                        queue.push(resolve);
                    }
                });
            },
            
            release() {
                if (queue.length > 0) {
                    const resolve = queue.shift();
                    resolve();
                } else {
                    current--;
                }
            }
        };
    }
    
    async readFile(filepath) {
        try {
            const content = await fs.readFile(filepath, 'utf8');
            return content;
        } catch (error) {
            console.error(`Error reading ${filepath}:`, error.message);
            return null;
        }
    }
    
    async processContent(content, filename) {
        // Simulate processing time
        await new Promise(resolve => setTimeout(resolve, 100));
        
        return {
            filename,
            lines: content.split('\n').length,
            words: content.split(/\s+/).length,
            characters: content.length,
            processedAt: new Date().toISOString()
        };
    }
    
    async writeResult(result, outputDir) {
        const outputFile = path.join(outputDir, `${result.filename}_analysis.json`);
        
        try {
            await fs.writeFile(outputFile, JSON.stringify(result, null, 2));
        } catch (error) {
            console.error(`Error writing ${outputFile}:`, error.message);
        }
    }
    
    async processFile(filepath, outputDir) {
        await this.semaphore.acquire();
        
        try {
            // Read file
            const content = await this.readFile(filepath);
            if (!content) return null;
            
            // Process content
            const filename = path.basename(filepath);
            const result = await this.processContent(content, filename);
            
            // Write result
            await this.writeResult(result, outputDir);
            
            console.log(`Processed: ${filepath}`);
            return result;
            
        } finally {
            this.semaphore.release();
        }
    }
    
    async processMultipleFiles(filepaths, outputDir) {
        // Ensure output directory exists
        await fs.mkdir(outputDir, { recursive: true });
        
        const promises = filepaths.map(filepath => 
            this.processFile(filepath, outputDir)
        );
        
        const results = await Promise.allSettled(promises);
        return results
            .filter(result => result.status === 'fulfilled' && result.value)
            .map(result => result.value);
    }
}

// 4. Real-time data streaming
class AsyncDataStreamer {
    constructor() {
        this.subscribers = new Set();
        this.running = false;
        this.streamTask = null;
    }
    
    subscribe(callback) {
        this.subscribers.add(callback);
        return () => this.unsubscribe(callback); // Return unsubscribe function
    }
    
    unsubscribe(callback) {
        this.subscribers.delete(callback);
    }
    
    async broadcast(data) {
        if (this.subscribers.size > 0) {
            const promises = Array.from(this.subscribers).map(callback => {
                try {
                    return callback(data);
                } catch (error) {
                    console.error('Subscriber error:', error);
                    return Promise.resolve();
                }
            });
            
            await Promise.allSettled(promises);
        }
    }
    
    async start() {
        if (this.running) return;
        
        this.running = true;
        let counter = 0;
        
        this.streamTask = (async () => {
            while (this.running) {
                const data = {
                    timestamp: new Date().toISOString(),
                    counter,
                    value: counter * 2 + 1,
                    random: Math.random()
                };
                
                await this.broadcast(data);
                counter++;
                
                // Stream every second
                await new Promise(resolve => setTimeout(resolve, 1000));
            }
        })();
        
        return this.streamTask;
    }
    
    async stop() {
        this.running = false;
        if (this.streamTask) {
            await this.streamTask;
            this.streamTask = null;
        }
    }
}

// 5. Event-driven architecture
class AsyncEventEmitter {
    constructor() {
        this.events = new Map();
    }
    
    on(event, listener) {
        if (!this.events.has(event)) {
            this.events.set(event, []);
        }
        this.events.get(event).push(listener);
        
        // Return unsubscribe function
        return () => this.off(event, listener);
    }
    
    off(event, listener) {
        const listeners = this.events.get(event);
        if (listeners) {
            const index = listeners.indexOf(listener);
            if (index > -1) {
                listeners.splice(index, 1);
            }
        }
    }
    
    async emit(event, data) {
        const listeners = this.events.get(event);
        if (listeners && listeners.length > 0) {
            const promises = listeners.map(listener => {
                try {
                    return listener(data);
                } catch (error) {
                    console.error(`Event listener error for ${event}:`, error);
                    return Promise.resolve();
                }
            });
            
            return Promise.allSettled(promises);
        }
    }
    
    once(event, listener) {
        const onceListener = async (data) => {
            this.off(event, onceListener);
            return listener(data);
        };
        
        return this.on(event, onceListener);
    }
}

// 6. Application orchestrator
class AsyncApplication {
    constructor() {
        this.eventEmitter = new AsyncEventEmitter();
        this.services = new Map();
        this.running = false;
    }
    
    registerService(name, service) {
        this.services.set(name, service);
    }
    
    getService(name) {
        return this.services.get(name);
    }
    
    async start() {
        if (this.running) return;
        
        this.running = true;
        console.log('Starting async application...');
        
        // Initialize services
        for (const [name, service] of this.services) {
            if (typeof service.start === 'function') {
                await service.start();
                console.log(`Service ${name} started`);
            }
        }
        
        await this.eventEmitter.emit('app:started');
    }
    
    async stop() {
        if (!this.running) return;
        
        this.running = false;
        console.log('Stopping async application...');
        
        // Shutdown services in reverse order
        const serviceEntries = Array.from(this.services.entries()).reverse();
        
        for (const [name, service] of serviceEntries) {
            if (typeof service.stop === 'function') {
                await service.stop();
                console.log(`Service ${name} stopped`);
            }
        }
        
        await this.eventEmitter.emit('app:stopped');
    }
    
    on(event, listener) {
        return this.eventEmitter.on(event, listener);
    }
    
    emit(event, data) {
        return this.eventEmitter.emit(event, data);
    }
}

// 7. Performance monitoring
class AsyncPerformanceMonitor {
    constructor() {
        this.metrics = {
            startTime: null,
            endTime: null,
            operations: 0,
            errors: 0,
            avgResponseTime: 0,
            responseTime: []
        };
    }
    
    start() {
        this.metrics.startTime = Date.now();
        return this;
    }
    
    recordOperation(responseTime) {
        this.metrics.operations++;
        this.metrics.responseTime.push(responseTime);
        this.metrics.avgResponseTime = 
            this.metrics.responseTime.reduce((a, b) => a + b, 0) / 
            this.metrics.responseTime.length;
    }
    
    recordError() {
        this.metrics.errors++;
    }
    
    stop() {
        this.metrics.endTime = Date.now();
        this.metrics.totalTime = this.metrics.endTime - this.metrics.startTime;
        return this.getReport();
    }
    
    getReport() {
        return {
            totalTime: this.metrics.totalTime,
            operations: this.metrics.operations,
            errors: this.metrics.errors,
            avgResponseTime: this.metrics.avgResponseTime,
            opsPerSecond: this.metrics.operations / (this.metrics.totalTime / 1000),
            errorRate: this.metrics.errors / this.metrics.operations
        };
    }
}

// 8. Example usage
async function demonstrateAsyncPatterns() {
    console.log('=== JavaScript Async Patterns Demo ===');
    
    const monitor = new AsyncPerformanceMonitor().start();
    
    try {
        // Web scraping
        const scraper = new AsyncWebScraper({ maxConcurrent: 3, delay: 500 });
        const urls = [
            'https://httpbin.org/delay/1',
            'https://httpbin.org/json',
            'https://httpbin.org/uuid'
        ];
        
        const scrapingStart = Date.now();
        const scrapingResults = await scraper.scrapeMultiple(urls);
        monitor.recordOperation(Date.now() - scrapingStart);
        console.log(`Scraped ${scrapingResults.length} pages`);
        
        // File processing
        const processor = new AsyncFileProcessor(2);
        
        // Create dummy files
        await fs.mkdir('temp', { recursive: true });
        const files = ['temp/file1.txt', 'temp/file2.txt', 'temp/file3.txt'];
        
        for (const file of files) {
            await fs.writeFile(file, `Content of ${file}\nLine 2\nLine 3`);
        }
        
        const processingStart = Date.now();
        const processingResults = await processor.processMultipleFiles(files, 'output');
        monitor.recordOperation(Date.now() - processingStart);
        console.log(`Processed ${processingResults.length} files`);
        
        // Data streaming
        const streamer = new AsyncDataStreamer();
        const receivedData = [];
        
        const unsubscribe = streamer.subscribe(async (data) => {
            receivedData.push(data);
            console.log(`Received data: ${data.counter}`);
        });
        
        // Start streaming
        streamer.start();
        
        // Let it run for 3 seconds
        await new Promise(resolve => setTimeout(resolve, 3000));
        
        // Stop streaming
        await streamer.stop();
        unsubscribe();
        
        console.log(`Received ${receivedData.length} data points`);
        
        // Clean up
        await fs.rm('temp', { recursive: true, force: true });
        
    } catch (error) {
        console.error('Demo error:', error);
        monitor.recordError();
    }
    
    const report = monitor.stop();
    console.log('Performance Report:', report);
}

// Run the demonstration
demonstrateAsyncPatterns().catch(console.error);

// Export classes for use in other modules
module.exports = {
    AsyncWebScraper,
    AsyncDatabaseManager,
    AsyncFileProcessor,
    AsyncDataStreamer,
    AsyncEventEmitter,
    AsyncApplication,
    AsyncPerformanceMonitor
};
```
</PythonEditor>

## Summary

This module covered the fundamental differences in asynchronous programming between Python and JavaScript:

### Key Differences:

1. **Event Loop**: JavaScript has a single-threaded event loop, Python's asyncio runs on one thread but can integrate with thread pools
2. **Syntax**: JavaScript uses Promises and async/await, Python uses coroutines and asyncio
3. **Error Handling**: Different patterns for handling async errors and exceptions
4. **Concurrency**: JavaScript focuses on I/O concurrency, Python can combine asyncio with multiprocessing for CPU-bound tasks

### Key Concepts:

1. **Promise vs Coroutine**: Understanding the conceptual differences and usage patterns
2. **Event Loop Phases**: How JavaScript's event loop differs from Python's asyncio loop
3. **Coordination Primitives**: Different approaches to synchronization and coordination
4. **Real-world Patterns**: Practical applications like web scraping, database operations, and streaming

Understanding these asynchronous programming differences is crucial for Python developers transitioning to JavaScript, especially for backend development with Node.js and frontend applications requiring responsive user interfaces.
